use core::{ops::Deref, ptr, slice, usize};
use mlibs::cmsis_rtos2::utils::{AlignStore, ByteView};
use serde::{Deserialize, Serialize};
use crate::{driver::cmd_uart::CMD_UART, error::AppErr};

pub const HEAD0: u8 = 0xE1;
pub const HEAD1: u8 = 0x1E;
pub const END: u8 = 0xEF;

pub const TYPE_ACK: u8 = 0;
pub const TYPE_PING: u8 = 1;
pub const TYPE_PONG: u8 = 2;
pub const TYPE_SIMPLE_REQ: u8 = 3;
pub const TYPE_SIMPLE_RES: u8 = 4;
pub const TYPE_NOTIFY: u8 = 5;
pub const TYPE_NOTIFY_ACK: u8 = 6;
pub const TYPE_SESSION: u8 = 7;
pub const TYPE_REQ: u8 = 8;
pub const TYPE_RES: u8 = 9;

pub const CMD_OTA_START: u8 = 1;
pub const CMD_OTA_TRANSLATE: u8 = 2;
pub const CMD_OTA_COMPLETE: u8 = 3;

pub const CMD_STATUS: u8 = 4;
pub const CMD_LOG: u8 = 5;

pub fn uart_log(msg: &str) {
    _ = CMD_UART.send(TYPE_NOTIFY, 0, CMD_LOG, &msg);
}

pub trait ByteStream {
    fn recv(&self) -> ByteView;
    fn recv_with_timeout(&self, timeout: u32) -> Option<ByteView>;
}

pub struct StreamBuf<R> {
    stream: R,
    buf: ByteView,
}

impl<R: ByteStream> StreamBuf<R> {
    pub fn new(r: R) -> Self {
        Self {
            stream: r,
            buf: ByteView::null(),
        }
    }

    pub fn wait(&mut self) {
        if self.buf.is_empty() {
            self.buf = self.stream.recv();
        }
    }

    pub fn take_byte_with_timeout(&mut self, timeout: u32) -> Option<u8> {
        if self.buf.is_empty() {
            self.buf = self.stream.recv_with_timeout(timeout)?;
        }

        let v = self.buf[0];
        self.buf = self.buf.slice_from(1);
        Some(v)
    }

    pub fn take_buf(&mut self, ptr: *mut u8, len: usize, timeout: u32) -> Option<()> {
        let mut index = 0;
        while index < len {
            if self.buf.is_empty() {
                self.buf = self.stream.recv_with_timeout(timeout)?;
            }

            let mut n = len - index;
            if self.buf.len() < n {
                n = self.buf.len();
            }

            unsafe {
                ptr::copy_nonoverlapping(self.buf.as_ptr(), ptr.add(index), n);
            }
            self.buf = self.buf.slice_from(n);
            index += n;
        }

        Some(())
    }
}

pub struct Frame {
    bw: ByteView,
}

impl Frame {
    pub fn ctype(&self) -> u8 {
        self.bw[0]
    }

    pub fn seq(&self) -> u8 {
        self.bw[1]
    }

    pub fn into(self) -> CmdFrame {
        CmdFrame { frame: self }
    }
}

pub struct CmdFrame {
    frame: Frame,
}

// type, seq, cmd, data
impl CmdFrame {
    pub fn cmd(&self) -> u8 {
        self.bw[2]
    }

    pub fn data(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.bw.as_ptr().add(3), self.bw.len() - 5) }
    }

    pub fn parse<'a, T: Deserialize<'a>>(&'a self) -> Result<T, AppErr> {
        //postcard::from_bytes(self.data()).map_err(|_| AppErr::Other("parse"))
        //serde_cbor::from_slice(self.data()).map_err(|_| AppErr::Other("parse"))
        minicbor_serde::from_slice(self.data()).map_err(|_| AppErr::Other("parse"))
    }
}

impl Deref for CmdFrame {
    type Target = Frame;
    fn deref(&self) -> &Self::Target {
        &self.frame
    }
}

pub struct ProtoReceiver<const SIZE: usize> {
    buf: AlignStore<SIZE>,
}

impl<const SIZE: usize> ProtoReceiver<SIZE> {
    pub const fn const_new() -> Self {
        Self {
            buf: AlignStore::const_new(),
        }
    }

    pub fn recv<'a, R: ByteStream>(&'a self, stream: &mut StreamBuf<R>) -> Frame {
        loop {
            stream.wait();

            if let Some(frame) = self.recv_impl(stream) {
                return frame;
            }
        }
    }

    fn recv_impl<'a, R: ByteStream>(&'a self, stream: &mut StreamBuf<R>) -> Option<Frame> {
        let len = self.sync(stream)? - 3;

        let bw = unsafe {
            stream.take_buf(self.buf.as_mut_ptr(), len, 10)?;

            let s = xor_sum(self.buf.bw_slice_to(len - 2));
            if s != self.buf[len - 2] {
                return None;
            }

            if END != self.buf[len - 1] {
                return None;
            }
            self.buf.bw_slice_to(len)
        };

        Some(Frame { bw })
    }

    fn sync<R: ByteStream>(&self, stream: &mut StreamBuf<R>) -> Option<usize> {
        let mut flag = false;
        loop {
            let v = stream.take_byte_with_timeout(10)?;
            if flag && (v == HEAD1) {
                break;
            }
            flag = v == HEAD0;
        }
        let v = stream.take_byte_with_timeout(10)?;
        if v < 7 {
            return None;
        }
        Some(v as usize)
    }
}

pub fn make_empty(ctype: u8, seq: u8) -> [u8; 7] {
    let mut buf = [HEAD0, HEAD1, 7, ctype, seq, 0, END];
    let s = xor_sum(unsafe { ByteView::const_new(buf.as_ptr().add(3), 2) });
    buf[5] = s;
    buf
}

pub fn make_res_empty(ctype: u8, seq: u8, ec: u8) -> [u8; 8] {
    let mut buf = [HEAD0, HEAD1, 8, ctype, seq, ec, 0, END];
    let s = xor_sum(unsafe { ByteView::const_new(buf.as_ptr().add(3), 3) });
    buf[6] = s;
    buf
}

/**
 * 0 head0
 * 1 head1
 * 2 size
 * 3 type
 * 4 seq
 * 5 ec
 * ... data
 * 6 + n sum
 * 7 + n end
 */
pub fn make_res<T: Serialize>(buf: &mut [u8], ctype: u8, seq: u8, ec_or_cmd: u8, value: &T) -> Result<usize, AppErr> {
    let data_buf = &mut buf[6..];
    let data_len = data_buf.len();
    let mut serial = minicbor_serde::Serializer::new(data_buf);
    value.serialize(&mut serial).map_err(|_| AppErr::Other("serial"))?;
    let len = data_len - serial.encoder().writer().len();

    buf[0] = HEAD0;
    buf[1] = HEAD1;
    buf[2] = (8 + len) as u8;
    buf[3] = ctype;
    buf[4] = seq;
    buf[5] = ec_or_cmd;
    buf[6 + len] = xor_sum2(&buf[3..(6 + len)]);
    buf[7 + len] = END;
    
    Ok(8 + len)
}

// pub fn make_res<T: Serialize>(ctype: u8, seq: u8, ec: u8, value: &T) -> Result<Box<[u8]>, AppErr> {

//     let mut data_vec = minicbor_serde::to_vec(value).map_err(|_| AppErr::Other("serial err"))?;
//     let mut buf = Vec::with_capacity(8 + data_vec.len());
//     buf.push(HEAD0);
//     buf.push(HEAD1);
//     buf.push(data_vec.len() as u8 + 8);
//     buf.push(ctype);
//     buf.push(seq);
//     buf.push(ec);
//     buf.append(&mut data_vec);
//     let s = xor_sum2(&buf[3..]);
//     buf.push(s);
//     buf.push(END);
//     Ok(buf.into_boxed_slice())
// }

fn xor_sum2(buf: &[u8]) -> u8 {
    let mut s = 0;
    for v in buf {
        s = s ^ *v;
    }
    s
}

fn xor_sum(buf: ByteView) -> u8 {
    let mut s = 0;
    for i in 0..buf.len() {
        s = s ^ buf[i];
    }
    s
}
